home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- **
- ** Example.c
- **
- ** Copyright: © 1992 by Apple Computer, Inc., all rights reserved.
- **
- ** This code snippet contains an entire application which uses
- ** the Asynchronous SCSI Manager to make an asynchronous read
- ** of block zero of a drive at SCSI ID 0. It is intended as
- ** example code only and not a basis for developing a driver or
- ** application which uses the Asynchronous SCSI Manager.
- **
- ****************************************************************/
-
- #include <scsi.h>
- #include <types.h>
- #include <stdio.h>
- #include <memory.h>
-
- #include <ACAM.h>
-
- /* We will move this into Traps.h eventually */
- #define _SCSIAtomic 0xA089
-
- /* Prototypes */
- OSErr ReadItt( DeviceIdent, ulong, ushort, Ptr );
-
- /* Constants */
- #define AUTOSENSE_SIZE 12
-
- /* Globals */
- SCSI_IO * scPB = 0;
- Ptr SenseBuffer = nil;
- Boolean working = true;
-
-
- main()
- {
- char buffer[0x200]; /* space to read block into */
- DeviceIdent device; /* device to read from */
- SCSIBusInquiryPB inqPB; /* Info about the scsi bus */
-
- device.bus = 0;
- device.targetID = 0;
- device.LUN = 0;
-
- /* Create and init a SCSI param block for the ReadItt function */
-
- /* First, get the size of a SCSI_IO for this bus */
- inqPB.scsiDevice = device;
- inqPB.scsiFlags = 0;
- inqPB.scsiFunctionCode = SCSIBusInquiry;
- inqPB.scsiCompletion = nil;
- inqPB.scsiPBLength = sizeof(SCSIBusInquiryPB);
-
- /* BusInquiry is always synchronous */
- SCSIAction( (SCSI_PB *) &inqPB );
-
- /* Then, allocate a block big enough */
-
- if( (scPB = (SCSI_IO *)NewPtrClear(inqPB.scsiIOpbSize)) == nil )
- return(1);
-
- scPB->scsiPBLength = inqPB.scsiIOpbSize;
-
- /* Allocate a block for Request Sense data */
-
- if( (SenseBuffer = NewPtrClear(AUTOSENSE_SIZE)) == nil )
- return(1);
-
- /* Read block 0 of SCSI ID 0 on Bus 0 */
-
- if( ReadItt( device, 0, 1, buffer ) )
- {
- DebugStr("\pBad Parameters");
- working = false; /* the completion routine isn't called */
- }
-
- /* SyncWait until we are done. */
- /*
- ** !!! DANGER WILL ROBINSON !!!
- **
- ** Don't do this in a driver! If you do this (SyncWait) when
- ** your driver is at a non-zero interrupt level you will wait a
- ** long time. The SCSI Manager needs interrrupts to get its work
- ** done. If you are a driver and get a synchronous call (to
- ** service a VM page fault for instance) you should either
- ** make an explicit synchronous call to the SCSI Manager - or
- ** make an async one and RTS to the Device Manager. The Device
- ** Mgr is aware of this problem and will do the necessary polling
- ** for interrupts.
- **
- */
- while( working )
- ;
- }
-
-
- pascal void
- CompFunc( SCSI_IO *ioPB)
- {
- /*
- ** Like, cool man - we're done.
- **
- ** We should inform the caller that the request completed.
- ** In a disk driver that would mean calling/jmping to IODone.
- **
- ** We should also do error handling here
- **
- ** Note that this routine could/will be called at interrupt time!
- **
- */
-
- /*
- ** Note the use of globals (working) - the SCSI Mgr sets up A5 to
- ** what it was when the SCSIAction call was made.
- */
- working = false;
-
- /*
- ** A quick word about error handling. As with the file system,
- ** synchronous requests at interrupt time are to be avoided. This
- ** means bad block re-mapping etc. will need to be done with an
- ** intelligent completion routine which can maintain its
- ** context across several transactions.
- */
- if( ioPB->scsiResult != noErr )
- DebugStr("\pYikes!");
- }
-
-
- /* ReadItt
- ** This function performs an asynchronous extended (10 byte) SCSI
- ** read command to an arbitrary target. If the SCSIAction trap
- ** returns an error then the parameter block was invalid and the
- ** transaction was NEVER— this means that the completion routine
- ** will NOT get called.
- */
-
- OSErr
- ReadItt(
- DeviceIdent device,
- ulong block,
- ushort numblks,
- Ptr buffer)
- {
- uchar *cmd;
-
- /*
- ** Please note that we are not passing Ptrs to local variables to
- ** the SCSI Manager. Since the transaction is not necessarily
- ** finished when this function completes we cannot be assured
- ** that variables in our local stack frame will still exist when
- ** they are needed.
- */
-
- cmd = (uchar *)&scPB->scsiCDB;
-
- /* Note that LUNs are dealt with in the Identify Message
- in SCSI2. If your device needs it, you can still stuff
- it into the CDB. */
-
- cmd[0] = 0x28; /* Extended Read Command */
-
- cmd[1] = 0;
-
- cmd[2] = block>>24;
- cmd[3] = block>>16;
- cmd[4] = block>>8;
- cmd[5] = block;
-
- cmd[6] = 0; /* reserved */
-
- cmd[7] = numblks>>8;
- cmd[8] = numblks;
- cmd[9] = 0; /* reserved */
-
- scPB->scsiCDBLength = 10;
-
- scPB->scsiFlags = (scsiSIMQNoFreeze | scsiDirectionIn | scsiDoDisconnect);
- scPB->scsiDevice = device;
- scPB->scsiCompletion = CompFunc; /* do it asynchronously */
- scPB->scsiTimeout = 0; /* no timeout for complete xaction */
-
- scPB->scsiDataPtr = buffer;
- scPB->scsiDataLength = numblks << 9; /* Assumes 512 bytes/sector */
- scPB->scsiDataType = scsiDataBuffer;
- scPB->scsiTransferType = scsiTransferBlind;
-
- scPB->scsiHandshake[0] = 1;
- scPB->scsiHandshake[1] = 511;
- scPB->scsiHandshake[2] = 0;
-
- scPB->scsiSensePtr = SenseBuffer; /* Autosense enabled by default - supply bfr */
- scPB->scsiSenseLength = AUTOSENSE_SIZE;
-
- scPB->scsiIOFlags = 0;
-
- scPB->scsiFunctionCode = SCSIExecIO;
- return( SCSIAction( (SCSI_PB *)scPB) );
- }
-
-